package cau.se.project.unittest;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;

import org.junit.Before;
import org.junit.Test;

import cau.se.project.data.CLSXGroup;
import cau.se.project.data.CLSXTreeModel;
import cau.se.project.data.DSMRow;
import cau.se.project.data.DependencyStructureMatrix;
import cau.se.project.data.method.GroupControl;
import cau.se.project.data.method.RowControl;
import cau.se.project.method.CLSXControl;
import cau.se.project.method.DSMControl;

public class CLSXTreeModelTest {
	private CLSXControl clsxTreeModel;
	private GroupControl parentRow;
	private RowControl dsmRow;
	private RowControl anotherRow;
	
	@Before
	public void setUp() throws Exception {
		this.clsxTreeModel = new CLSXTreeModel();
		this.parentRow = new CLSXGroup("ParentGroup");
		this.dsmRow = new DSMRow("TestRow");
		this.anotherRow = new DSMRow("AnotherRow");
	}

	@Test
	public void testCLSXTreeModelWithDSMControl() {
		DependencyStructureMatrix dsm = new DependencyStructureMatrix();
		dsm.insertRow(dsmRow, null);
		this.clsxTreeModel = new CLSXTreeModel(dsm);
		
		assertThat(this.clsxTreeModel.getDSM().getSize(), is(1));		
	}

	@Test
	public void testGetDSM() {
		DSMControl dsm = new DependencyStructureMatrix();
		dsm.insertRow(dsmRow, null);
		
		assertThat(this.clsxTreeModel.getDSM().getSize(), is(0));
		
		this.clsxTreeModel.addRow(dsmRow);
		
		assertThat(this.clsxTreeModel.getDSM().getSize(), is(1));
	}

	@Test
	public void testAddRow() {
		assertThat(((GroupControl)this.clsxTreeModel.getRoot()).getChildCount(), is(0));
		
		this.clsxTreeModel.addRow(this.dsmRow);
		
		assertThat(((GroupControl)this.clsxTreeModel.getRoot()).getChildCount(), is(1));
	}

	@Test
	public void testGetRoot() {
		assertNotNull(this.clsxTreeModel.getRoot());
	}

	@Test
	public void testGetChild() throws Exception {
		this.parentRow.addGroupMember(dsmRow);
		
		assertThat((RowControl)this.clsxTreeModel.getChild(this.parentRow, 0), is(dsmRow));
	}
	
	@Test(expected=NullPointerException.class)
	public void testGetChildWithException() {
		this.clsxTreeModel.getChild(null, -1);
	}

	@Test
	public void testGetChildCount() throws Exception {
		this.parentRow.addGroupMember(this.dsmRow);
		
		assertThat(this.clsxTreeModel.getChildCount(this.parentRow), is(1));
	}
	
	@Test(expected=NullPointerException.class)
	public void testGetChildCountWithException() {
		this.clsxTreeModel.getChildCount(null);
	}

	@Test
	public void testIsLeaf() throws Exception {
		assertFalse(this.clsxTreeModel.isLeaf(this.dsmRow));
		
		this.clsxTreeModel.addRow(this.dsmRow);
		
		assertTrue(this.clsxTreeModel.isLeaf(this.dsmRow));
	}

	@Test
	public void testGetIndexOfChild() throws Exception {
		assertThat(this.clsxTreeModel.getIndexOfChild(this.parentRow, this.dsmRow), is(-1));
		
		this.parentRow.addGroupMember(this.dsmRow);
		
		assertThat(this.clsxTreeModel.getIndexOfChild(this.parentRow, this.dsmRow), is(0));
	}
	
	@Test(expected=NullPointerException.class)
	public void testGetIndexOfChildWithException() {
		this.clsxTreeModel.getIndexOfChild(null, null);
	}
	
	@Test
	public void testMakeGroup() {
		GroupControl nameLessGroup = this.clsxTreeModel.makeGroup(null);
		assertThat(nameLessGroup.getClass(), is(CLSXGroup.class.getClass()));
		assertNull(nameLessGroup.getName());
		
		GroupControl testGroup = this.clsxTreeModel.makeGroup("TestGroup");		
		assertThat(testGroup.getClass(), is(CLSXGroup.class.getClass()));
		assertThat(testGroup.getName(), is("TestGroup"));
	}

	@Test
	public void testUnGroup() throws Exception {
		assertThat(this.parentRow.getChildCount(), is(0));
		this.parentRow.addGroupMember(this.dsmRow);
		assertThat(this.parentRow.getChildCount(), is(1));
		this.clsxTreeModel.addRow(this.parentRow);
		
		this.clsxTreeModel.unGroup(this.parentRow);
		
		assertThat((GroupControl)this.dsmRow.getParent(), is(not(this.parentRow)));
		assertThat((GroupControl)this.dsmRow.getParent(), is(this.clsxTreeModel.getRoot()));
	}

	@Test
	public void testMakeRow() {
		assertNull(this.clsxTreeModel.makeRow(null).getName());
		
		RowControl tempRow = this.clsxTreeModel.makeRow("TestRow");
		assertThat(tempRow.getClass(), is(DSMRow.class.getClass()));
		assertThat(tempRow.getName(), is("TestRow"));
	}

	@Test
	public void testRemoveRow() {
		assertThat(((GroupControl)this.clsxTreeModel.getRoot()).getChildCount(), is(0));
		
		this.clsxTreeModel.addRow(this.dsmRow);
		
		assertThat(((GroupControl)this.clsxTreeModel.getRoot()).getChildCount(), is(1));
		
		this.clsxTreeModel.removeRow(this.dsmRow);
		
		assertThat(((GroupControl)this.clsxTreeModel.getRoot()).getChildCount(), is(0));
	}

	@Test
	public void testMoveRowToWithIntPosition() throws Exception {
		this.clsxTreeModel.addRow(this.dsmRow);
		this.clsxTreeModel.addRow(this.anotherRow);
		
		assertThat((RowControl)this.clsxTreeModel.getChild(this.clsxTreeModel.getRoot(), 0), is(this.dsmRow));
		assertThat((RowControl)this.clsxTreeModel.getChild(this.clsxTreeModel.getRoot(), 1), is(this.anotherRow));
		
		this.clsxTreeModel.moveRowTo(1, 0);

		assertThat((RowControl)this.clsxTreeModel.getChild(this.clsxTreeModel.getRoot(), 0), is(this.anotherRow));
		assertThat((RowControl)this.clsxTreeModel.getChild(this.clsxTreeModel.getRoot(), 1), is(this.dsmRow));
	}
	
	@Test(expected=NullPointerException.class)
	public void testMoveRowToWithIntWithExceptionOne() throws Exception {
		this.clsxTreeModel.moveRowTo(-1, 10);
	}
	
	@Test(expected=NullPointerException.class)
	public void testMoveRowToWithIntWithExceptionTwo() throws Exception {
		this.clsxTreeModel.moveRowTo(10, 1);
	}
	
	@Test(expected=NullPointerException.class)
	public void testMoveRowToWithIntWithExceptionThree() throws Exception {
		this.clsxTreeModel.moveRowTo(10, -5);
	}

	@Test
	public void testMoveRowToWithRowControlPosition() throws Exception {
		this.clsxTreeModel.addRow(this.dsmRow);
		this.clsxTreeModel.addRow(this.anotherRow);
		
		assertThat((RowControl)this.clsxTreeModel.getChild(this.clsxTreeModel.getRoot(), 0), is(this.dsmRow));
		assertThat((RowControl)this.clsxTreeModel.getChild(this.clsxTreeModel.getRoot(), 1), is(this.anotherRow));
		
		this.clsxTreeModel.moveRowTo(this.anotherRow, this.dsmRow, true);

		assertThat((RowControl)this.clsxTreeModel.getChild(this.clsxTreeModel.getRoot(), 0), is(this.anotherRow));
		assertThat((RowControl)this.clsxTreeModel.getChild(this.clsxTreeModel.getRoot(), 1), is(this.dsmRow));
	}
	
	@Test(expected=NullPointerException.class)
	public void testMoveRowToWithRowControlPositionWithExceptionOne() throws Exception {
		this.clsxTreeModel.moveRowTo(null, this.anotherRow, true);
	}
	
	@Test(expected=NullPointerException.class)
	public void testMoveRowToWithRowControlPositionWithExceptionTwo() throws Exception {
		this.clsxTreeModel.moveRowTo(this.dsmRow, null, true);
	}

	@Test
	public void testSortMatrix() throws Exception {
		this.clsxTreeModel.addRow(this.dsmRow);
		this.clsxTreeModel.addRow(this.anotherRow);
		
		assertThat((RowControl)this.clsxTreeModel.getChild(this.clsxTreeModel.getRoot(), 0), is(this.dsmRow));
		assertThat((RowControl)this.clsxTreeModel.getChild(this.clsxTreeModel.getRoot(), 1), is(this.anotherRow));
		
		this.clsxTreeModel.sortMatrix((GroupControl) this.clsxTreeModel.getRoot());

		assertThat((RowControl)this.clsxTreeModel.getChild(this.clsxTreeModel.getRoot(), 0), is(this.anotherRow));
		assertThat((RowControl)this.clsxTreeModel.getChild(this.clsxTreeModel.getRoot(), 1), is(this.dsmRow));
		
		GroupControl tempRow = new CLSXGroup("D");
		this.clsxTreeModel.addRow(tempRow);

		assertThat((GroupControl)this.clsxTreeModel.getChild(this.clsxTreeModel.getRoot(), 2), is(tempRow));
		
		this.clsxTreeModel.sortMatrix((GroupControl) this.clsxTreeModel.getRoot());

		assertThat((RowControl)this.clsxTreeModel.getChild(this.clsxTreeModel.getRoot(), 0), is(this.anotherRow));
		assertThat((GroupControl)this.clsxTreeModel.getChild(this.clsxTreeModel.getRoot(), 1), is(tempRow));
		assertThat((RowControl)this.clsxTreeModel.getChild(this.clsxTreeModel.getRoot(), 2), is(this.dsmRow));
	}

	/*
	@Test
	public void testDoPartition() {
		fail("Not yet implemented");
	}
	*/

	@Test
	public void testGetArray() {
		assertThat(this.clsxTreeModel.getArray(), is(new int[][] {}));
		
		this.clsxTreeModel.addRow(this.dsmRow);
		
		assertThat(this.clsxTreeModel.getArray(), is(new int[][] {{0}}));
		
		this.clsxTreeModel.addRow(this.anotherRow);
		
		assertThat(this.clsxTreeModel.getArray(), is(new int[][] { {0, 0} , {0, 0} }));
	}

	@Test
	public void testGetNameList() {
		assertNull(this.clsxTreeModel.getNameList());
		
		this.clsxTreeModel.addRow(this.dsmRow);
		
		assertThat(this.clsxTreeModel.getNameList(), is(new String[] {"TestRow"}));
		
		this.clsxTreeModel.addRow(this.anotherRow);
		
		assertThat(this.clsxTreeModel.getNameList(), is(new String[] {"TestRow", "AnotherRow"}));
	}

	@Test
	public void testSetDependency() {
		this.clsxTreeModel.addRow(dsmRow);
		this.clsxTreeModel.addRow(anotherRow);
		
		assertTrue(dsmRow.getDepenencyList().isEmpty());
		this.clsxTreeModel.setDependency(0, 1, true);

		assertThat(dsmRow.getDepenencyList().size(), is(1));
	}

	@Test
	public void testMoveUpOne() throws Exception {
		this.clsxTreeModel.addRow(this.dsmRow);
		this.clsxTreeModel.addRow(this.anotherRow);
		
		assertThat(this.clsxTreeModel.getDSM().getRow(0), is(this.dsmRow));
		assertThat(this.clsxTreeModel.getDSM().getRow(1), is(this.anotherRow));

		this.clsxTreeModel.moveUp(this.anotherRow);
		
		assertThat(this.clsxTreeModel.getDSM().getRow(0), is(this.anotherRow));
		assertThat(this.clsxTreeModel.getDSM().getRow(1), is(this.dsmRow));
	}
	
	@Test(expected=NullPointerException.class)
	public void testMoveUpWithExceptionTwo() throws Exception {
		this.clsxTreeModel.moveUp(this.dsmRow);
	}
	
	@Test
	public void testMoveUpTwo() throws Exception {
		this.clsxTreeModel.addRow(this.dsmRow);
		
		assertThat(this.clsxTreeModel.getDSM().getRow(0), is(this.dsmRow));

		this.clsxTreeModel.moveUp(this.dsmRow);
		
		assertThat(this.clsxTreeModel.getDSM().getRow(0), is(this.dsmRow));
	}

	@Test
	public void testMoveDownOne() throws Exception {
		this.clsxTreeModel.addRow(this.dsmRow);
		this.clsxTreeModel.addRow(this.anotherRow);

		assertThat(this.clsxTreeModel.getDSM().getRow(0), is(this.dsmRow));
		assertThat(this.clsxTreeModel.getDSM().getRow(1), is(this.anotherRow));

		this.clsxTreeModel.moveDown(this.dsmRow);
		
		assertThat(this.clsxTreeModel.getDSM().getRow(0), is(this.anotherRow));
		assertThat(this.clsxTreeModel.getDSM().getRow(1), is(this.dsmRow));
	}
	

	@Test
	public void testMoveDownTwo() throws Exception {
		this.clsxTreeModel.addRow(this.dsmRow);

		assertThat(this.clsxTreeModel.getDSM().getRow(0), is(this.dsmRow));

		this.clsxTreeModel.moveDown(this.dsmRow);
		
		assertThat(this.clsxTreeModel.getDSM().getRow(0), is(this.dsmRow));
	}
	
	@Test(expected=NullPointerException.class)
	public void testMoveDownWithException() throws Exception {
		this.clsxTreeModel.moveDown(this.dsmRow);
	}
}
